<script setup>
import { ref, onMounted, computed } from 'vue'
import { sessionApi, listDictsApi, treeDictsApi, sortDictApi, saveDictApi, delDictsApi, oneDictApi } from '@/commons/api'
import routes from '@/commons/router'
import Msg from '@/components/message'
import Confirm from '@/components/confirm'
import { CScrollbar } from 'c-scrollbar'
import Loader from '@/components/loader/Loader.vue'
import TreeSel from '@/components/cascader/TreeSel.vue'
import { formatDate } from '@/commons/filter'
import Upload from '@/components/upload/Upload.vue'

const loadShow = ref(false)

// 界面挂载前处理
onMounted(() => {
  // 获取用户会话信息
  checkAuth()
})

const procAuth = ref({
  addAuth: false,
  delAuth: false,
  edtAuth: false,
})
// checkAuth 获取权限
const checkAuth = async () => {
  loadShow.value = true
  try {
    const res = await sessionApi()
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      const userBtnCode = res.data.btnCodes
      procAuth.value = {
        addAuth: userBtnCode.indexOf('1001010601') !== -1,
        delAuth: userBtnCode.indexOf('1001010602') !== -1,
        edtAuth: userBtnCode.indexOf('1001010603') !== -1,
      }
      await listTypes()
    } else {
      localStorage.removeItem("token")
      Msg({ kind: 'error', txt: res.msg })
      routes.replace('/login')
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// listTypes 列表展示分类
const typeList = ref([])
const actType = ref({ typeId: '', typeName: '', typeCode: '' })
const listTypes = async () => {
  typeList.value = []
  const res = await listDictsApi({ kind: 1, typeCode: '' })
  if(res.code === import.meta.env.VITE_SUCCESS_CODE && res.data && res.data.length>0) {
    typeList.value = res.data
    actType.value = { typeId: typeList.value[0].dictId, typeName: typeList.value[0].dictName, typeCode: typeList.value[0].dictCode }
    await listDicts()
  }
}

// 分类对象
const typeModal = ref(false)
const typeForm = ref({
  dictId: '',
  dictName: '',
  dictCode: '',
  kind: 1,
  typeId: '111111111111111111111',
  typeCode: 'FLBM',
  parentId: '',
  sort: 0,
  remarks: ''
})

// addType 添加分类
const addType = () => {
  typeModal.value = true
  treeDicts(1, '')
}

// updType 修改分类
const updType = async (dictId) => {
  const res = await oneDictApi({ dictId })
  if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
    typeForm.value = res.data
    typeModal.value = true
    await treeDicts(1, '')
  } else {
    Msg({ kind: 'error', txt: res.msg })
  }
}

// saveType 保存分类提交
const saveType = async () => {
  let typeName = typeForm.value.dictName
  let typeCode = typeForm.value.dictCode
  let parentId = typeForm.value.parentId
  let sort = parseInt(typeForm.value.sort)
  if(typeName === '' || typeName.length > 30) {
    Msg({ kind: 'warn', txt: '分类名称不能为空，且长度不多于30个字符！' })
    return
  }
  if(typeCode === '' || typeCode.length > 30) {
    Msg({ kind: 'warn', txt: '分类编码不能为空，且长度不多于30个字符！' })
    return
  }
  if(parentId === '' || parentId.length !== 21) {
    Msg({ kind: 'warn', txt: '父级分类编号不能为空，且长度为21个字符！' })
    return
  }
  typeForm.value.sort = sort
  loadShow.value = true
  try {
    const res = await saveDictApi(typeForm.value)
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      closeModal(1)
      await listTypes()
      Msg({ kind: 'success', txt: '恭喜您，分类保存成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// delType 删除分类
const delType = (typeId) => {
  Confirm('确定要处理选中的分类吗？').then(() => {
    delTypeProc(typeId)
  }).catch(() => {
    Msg({ kind: 'info', txt: "您取消了处理选中数据的操作~！" })
  })
}

const delTypeProc = async (typeId) => {
  loadShow.value = true
  try {
    const res = await delDictsApi({ dictIds: typeId })
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      await listTypes()
      Msg({ kind: 'success', txt: '恭喜您，分类删除成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch(e) {
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
    loadShow.value = false
  }
}

// setType 筛选数据字典项
const setType = (type) => {
  actType.value = { typeId: type.dictId, typeName: type.dictName, typeCode: type.dictCode }
  listDicts()
}

const dictList = ref([])
const hasData = ref(false)
// listDicts 列表展示
const listDicts = async () => {
  hasData.value = false
  loadShow.value = true
  try {
    const res = await listDictsApi({ kind: 2, typeCode: actType.value.typeCode })
    if(res.code === import.meta.env.VITE_SUCCESS_CODE && res.data && res.data.length>0) {
      hasData.value = true
      dictList.value = res.data
      idList.value = []
      checkList.value = []
      allCheck.value = false
      res.data.forEach(() => {
        checkList.value.push(false)
      })
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// 选择效果实现
const idList = ref([])
const checkList = ref([])
const allCheck = ref(false)
// checkAll 全选
const checkAll = () => {
  idList.value = []
  checkList.value = []
  allCheck.value = !allCheck.value
  if(allCheck.value) {
    typeList.value.forEach(item => {
      idList.value.push(item.typeId)
      checkList.value.push(true)
    })
  } else {
    typeList.value.forEach(() => {
      checkList.value.push(false)
    })
  }
}
// checkCurId 单选
const checkCurId = (idx, typeId) => {
  if(!checkList.value[idx]) {
    idList.value.push(typeId)
  } else {
    idList.value.splice(idList.value.findIndex(id => id === typeId), 1)
  }
  checkList.value[idx] = !checkList.value[idx]
}

const showModal = ref(false)
const dictForm = ref({
  dictId: '',
  dictName: '',
  shortName: '',
  fullName: '',
  dictCode: '',
  logoId: '',
  logoName: '',
  logoUrl: '',
  kind: 2,
  typeId: actType.value.typeId,
  typeCode: actType.value.typeCode,
  parentId: '',
  parentName: '',
  parentCode: '',
  sort: 0,
  remarks: ''
})

// addDict 新增
const imgRef = ref()
const addDict = () => {
  if(actType.value.typeId === '') {
    Msg({ kind: 'warn', txt: '请先添加数据字典的分类' })
    return
  }
  treeDicts(2, actType.value.typeCode)
  showModal.value = true
}

// updDict 修改
const updDict = async (dictId) => {
  loadShow.value = true
  try {
    const res = await oneDictApi({ dictId })
    if (res.code === import.meta.env.VITE_SUCCESS_CODE) {
      dictForm.value = res.data
      if (dictForm.value.logoId && dictForm.value.logoId !== '') {
        imgRef.value = {
          id: dictForm.value.logoId,
          name: dictForm.value.logoName,
          url: dictForm.value.logoUrl,
          thumb: dictForm.value.logoUrl.replace('/img', '/img/thumb')
        }
      }
      await treeDicts(2, actType.value.typeCode)
      showModal.value = true
    } else {
      Msg({kind: 'info', txt: '暂无内容'})
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// saveDict 保存提交
const saveDict = async () => {
  let dictId = dictForm.value.dictId
  let dictName = dictForm.value.dictName
  let dictCode = dictForm.value.dictCode
  let parentId = dictForm.value.parentId
  let sort = parseInt(dictForm.value.sort)
  if(dictName === '' || dictName.length > 50) {
    Msg({ kind: 'warn', txt: '字典的名称不能为空，且长度不超过50个字符' })
    return
  } else if(dictCode === '' || dictCode.length > 30) {
    Msg({ kind: 'warn', txt: '字典的编码不能为空' })
    return
  } else if(parentId === '' || parentId.length !== 21) {
    Msg({ kind: 'warn', txt: '字典分类不能为空' })
    return
  } else if(sort < 1) {
    Msg({ kind: 'warn', txt: '分类排序不能为空' })
    return
  } else if(dictId === parentId) {
    Msg({ kind: 'warn', txt: '不可选择当前分类为父级分类' })
    return
  }
  dictForm.value.sort = sort
  if(imgRef.value && imgRef.value.id && imgRef.value.id!=='') {
    dictForm.value.logoId = imgRef.value.id
    dictForm.value.logoName = imgRef.value.name
    dictForm.value.logoUrl = imgRef.value.url
  } else {
    dictForm.value.logoId = ''
    dictForm.value.logoName = ''
    dictForm.value.logoUrl = ''
  }
  loadShow.value = true
  try {
    dictForm.value.typeId = actType.value.typeId
    dictForm.value.typeCode = actType.value.typeCode
    const res = await saveDictApi(dictForm.value)
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      closeModal(2)
      await listDicts()
      Msg({ kind: 'success', txt: '恭喜您，数据字典保存成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// closeModal 关闭弹出层，并重置表单数据
const closeModal = (kind) => {
  switch (kind) {
    case 1:
      typeModal.value = false
      typeForm.value = {
        dictId: '',
        dictName: '',
        dictCode: '',
        kind: 1,
        typeId: '111111111111111111111',
        typeCode: 'FLBM',
        parentId: '',
        sort: 0,
        remarks: ''
      }
      break
    case 2:
      showModal.value = false
      dictForm.value = {
        dictId: '',
        dictName: '',
        shortName: '',
        fullName: '',
        dictCode: '',
        logoId: '',
        logoName: '',
        logoUrl: '',
        kind: 2,
        typeId: actType.value.typeId,
        typeCode: actType.value.typeCode,
        parentId: '',
        parentName: '',
        parentCode: '',
        sort: 0,
        remarks: ''
      }
      imgRef.value = null
      break
  }
}

// delDicts 批量删除数据
const delDicts = async() => {
  if(!idList || idList.value.length===0) {
    Msg({ kind: 'warn', txt: '请至少选择一项再删除！' })
    return
  }
  Confirm('确定这样删除选中的数据吗？').then(() => {
    delDictsProc()
  }).catch(() => {
    Msg({ kind: 'info', txt: "取消删除选中的数据！" })
  })
}
// delDictsProc 删除分类实现，分离出来防止调用时异步报错
const delDictsProc = async () => {
  let dictIds = idList.value.join(',')
  loadShow.value = true
  try {
    const res = await delDictsApi({ dictIds, kind: 2 })
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      await listDicts()
      Msg({ kind: 'success', txt: '恭喜您，数据字典删除成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch(e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统异常，请联系管理员！' + e })
  }
}

// 获取字典树
const typeTree = ref([])
const dictTree = ref([])
const treeDicts = async (kind, typeCode) => {
  const res = await treeDictsApi({ kind, typeCode })
  if(res.code === import.meta.env.VITE_SUCCESS_CODE && res.data && res.data.length > 0) {
    if(kind === 1) {
      typeTree.value = res.data
    } else {
      dictTree.value = res.data
    }
  } else {
    if(kind === 1) {
      typeTree.value = []
    } else {
      dictTree.value = []
    }
  }
  if(kind === 1) {
    typeTree.value.unshift({
      selId: '111111111111111111111',
      selName: '一级分类',
      selCode: '1000',
      parentId: '000000000000000000000',
      chked: false,
      children: null
    })
  } else {
    dictTree.value.unshift({
      selId: '111111111111111111111',
      selName: '一级字典分类',
      selCode: '1000',
      parentId: '000000000000000000000',
      chked: false,
      children: null
    })
  }
}

const setValue = (item, kind) => {
  if(kind === 1) {
    sortDict(kind, '', item.selId)
    typeForm.value.parentId = item.selId
    typeForm.value.parentName = item.selName
    typeForm.value.parentCode = item.selCode
  } else {
    sortDict(kind, actType.value.typeCode, item.selId)
    dictForm.value.parentId = item.selId
    dictForm.value.parentName = item.selName
    dictForm.value.parentCode = item.selCode
  }
}

// sortDict 排序
const sortDict = async (kind, typeId, parentId) => {
  const res = await sortDictApi({ kind, typeId, parentId })
  if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
    if(kind === 1) {
      typeForm.value.sort = res.data
    } else {
      dictForm.value.sort = res.data
    }
  }
}

// fmtDate 时间戳转时间
const fmtDate = computed(() => {
  return (time, kind) => {
    let date = new Date(time*1000)
    return formatDate(date, kind)
  }
})

// setUrl 回调获取上传文件的地址
const setUrl = (kind, types, file) => {
  imgRef.value = file
}
</script>

<template>
  <div class="a">
    <div class="b">
      <div class="c">
        <div class="d">
          <div class="e">数据字典分类</div>
          <div v-if="procAuth.addAuth" class="btn-pi" title="新增" @click="addType"><i class="iconfont">&#xea2d;</i> 新增</div>
        </div>
        <c-scrollbar v-if="typeList && typeList.length>0" class="f">
          <div v-for="curType in typeList" :key="curType.dictId" :class="['g cur', actType.typeId===curType.dictId ? 'h' : '']">
            <div class="i dan" :style="{'padding-left': (curType.level-1)*10+'px'}" @click="setType(curType)">{{ curType.dictName }}[{{ curType.dictCode }}]({{ curType.nums }})</div>
            <div class="color-w mr5" v-if="procAuth.edtAuth" @click="updType(curType.dictId)"><i class="iconfont">&#xea48;</i></div>
            <div class="color-e" v-if="procAuth.delAuth" @click="delType(curType.dictId)"><i class="iconfont">&#xea45;</i></div>
          </div>
        </c-scrollbar>
        <div v-else class="no-data">暂无内容</div>
      </div>
      <div class="j">
        <c-scrollbar>
          <div class="k">
            <div class="l">
              <div v-if="procAuth.addAuth" class="btn-pi mr15" title="新增" @click="addDict"><i class="iconfont">&#xea2d;</i> 新增</div>
              <div v-if="procAuth.delAuth" class="btn-de mr15" title="删除" @click="delDicts"><i class="iconfont">&#xea45;</i> 删除</div>
              <div class="btn-r mr15" title="刷新" @click="listDicts"><i class="iconfont">&#xea8c;</i></div>
            </div>
            <div class="m"><i class="iconfont">&#xeaaa;</i> 当前位置：工作台 > 系统管理 > 数据字典管理</div>
          </div>
          <div v-if="hasData">
            <table>
              <tbody>
              <tr>
                <th style="width: 5%;"><span @click="checkAll()" title="全选"><i :class="['iconfont', allCheck ? 'chked' : 'chk']" v-html="allCheck ? '&#xea3a;' : '&#xea46;'" /></span></th>
                <th style="width: 25%;">名称</th><th style="width: 20%;">简称</th><th style="width: 10%;">编码</th>
                <th style="width: 10%;">排序</th><th style="width: 20%;">时间</th><th style="width: 10%;">操作</th>
              </tr>
              <tr v-for="(curDict, index) in dictList" :key="curDict.dictId" class="tr-style">
                <td class="txt-center"><span @click="checkCurId(index, curDict.dictId)" title="选择"><i :class="['iconfont', checkList[index] ? 'chked' : 'chk']" v-html="checkList[index]  ? '&#xe685;' : '&#xe686;'" /></span></td>
                <td><div :style="{'padding-left': curDict.level*15+'px'}">{{curDict.dictName}}</div></td>
                <td class="txt-center">{{curDict.shortName}}</td>
                <td class="txt-center">{{curDict.dictCode}}</td>
                <td class="txt-center">{{curDict.sort}}</td>
                <td class="txt-center">{{fmtDate(curDict.addTime, 2)}}</td>
                <td class="txt-center">
                  <span v-if="procAuth.edtAuth" class="cl-warn" title="修改" @click="updDict(curDict.dictId)"><i class="iconfont">&#xea48;</i> 修 改</span>
                </td>
              </tr>
              </tbody>
            </table>
          </div>
          <div v-else class="no-data">暂无内容</div>
        </c-scrollbar>
      </div>
    </div>

    <!-- 新增、修改弹出层 -->
    <transition name="fade-mod" appear>
      <div v-if="typeModal" class="modal-backdrop">
        <c-scrollbar>
          <div class="modal" style="width: 500px;">
            <div class="modal-header">
              <div class="header-left"><i class="iconfont">&#xea54;</i> 保存数据字典分类信息</div>
              <div class="header-right" @click="closeModal(1)"><i class="iconfont fs22">&#xea7f;</i></div>
            </div>
            <div class="modal-body">
              <div>
                <div class="ipt-title"><span class="required">*</span>父级分类</div>
                <tree-sel :tree-list="typeTree" :kind="1" :inboxed="false" :curName="typeForm.parentName ? typeForm.parentName+'['+typeForm.parentCode+']' : ''" pre-name="父级分类" @setValue="setValue" />
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>数据字典排序</div>
                <div><input type="text" v-model="typeForm.sort" maxlength="11" placeholder="请输入分类排序" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>分类名称</div>
                <div><input type="text" v-model="typeForm.dictName" maxlength="50" placeholder="请输入分类名称" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>分类编码</div>
                <div><input type="text" v-model="typeForm.dictCode" maxlength="50" placeholder="请输入分类编码" class="ipt" /></div>
              </div>
            </div>
            <div class="modal-footer">
              <div class="btn-pi mr15" @click="saveType"><i class="iconfont">&#xea90;</i> 保存</div>
              <div class="btn-d" @click="closeModal(1)"><i class="iconfont">&#xea4f;</i> 取消</div>
            </div>
          </div>
        </c-scrollbar>
      </div>
    </transition>

    <!-- 新增、修改弹出层 -->
    <transition name="fade-mod" appear>
      <div v-if="showModal" class="modal-backdrop">
        <c-scrollbar>
          <div class="modal" style="width: 600px;">
            <div class="modal-header">
              <div class="header-left"><i class="iconfont">&#xea54;</i> 保存数据字典</div>
              <div class="header-right" @click="closeModal(2)"><i class="iconfont fs22">&#xea7f;</i></div>
            </div>
            <div class="modal-body">
              <div>
                <div class="ipt-title"><span class="required">*</span>父级分类</div>
                <tree-sel :tree-list="dictTree" :kind="2" :inboxed="false" :curName="dictForm.parentName ? dictForm.parentName+'['+dictForm.parentCode+']' : ''" pre-name="父级分类" @setValue="setValue" />
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>数据字典排序</div>
                <div><input type="text" v-model="dictForm.sort" maxlength="11" placeholder="请输入分类排序" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>数据字典名称</div>
                <div><input type="text" v-model="dictForm.dictName" maxlength="85" placeholder="请输入分类名称" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>数据字典编码</div>
                <div><input type="text" v-model="dictForm.dictCode" maxlength="50" placeholder="请输入分类编码" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required"></span>数据字典全称</div>
                <div><input type="text" v-model="dictForm.fullName" maxlength="85" placeholder="请输入分类全称" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required"></span>数据字典简称</div>
                <div><input type="text" v-model="dictForm.shortName" maxlength="85" placeholder="请输入分类简称" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required"></span>数据字典图标</div>
                <div><upload :kind="1" :types="1" :file="imgRef" @setUrl="setUrl" /></div>
              </div>
            </div>
            <div class="modal-footer">
              <div class="btn-pi mr15" @click="saveDict"><i class="iconfont">&#xea90;</i> 保存</div>
              <div class="btn-d" @click="closeModal(2)"><i class="iconfont">&#xea4f;</i> 取消</div>
            </div>
          </div>
        </c-scrollbar>
      </div>
    </transition>
    <loader :loadShow="loadShow" />
  </div>
</template>

<style scoped>
.a {width: 100%; height: 100%; overflow: hidden;}
.b {width: 100%; height: 100%; display: flex; display: -webkit-flex;}
.c {width: 279px; height: 100%; border-right: 1px solid #DDD;}
.d {width: calc(100% - 20px); display: flex; display: -webkit-flex; padding: 10px; border-bottom: 1px solid #DDD;}
.e {flex-grow: 1; height: 35px; line-height: 35px; font-size: 16px;}
.f {height: calc(100% - 45px);}
.g {width: calc(100% - 20px); display: flex; display: -webkit-flex; background-color: #fff; padding: 15px 10px; border-bottom: 1px solid #DDD; cursor: pointer;}
.g:hover {background-color: #e9f3fe;}
.h {background-color: #e9f3fe;}
.i {flex-grow: 1;}
.j {height: calc(100% - 16px); flex-grow: 1; padding: 10px;}
.k {padding: 0 20px 10px 20px; display: flex; display: -webkit-flex;}
.l {display: inline-flex; display: -webkit-inline-flex;}
.m {flex-grow: 1; text-align: right; padding-top: 10px; color: #666;}
.n {border: 1px dashed #DDD; padding: 15px; display: flex; display: -webkit-flex; margin-bottom: 10px;}
.o {width: 240px; height: 28px; padding-left: 10px;}
.o:focus {border: 1px solid #66B1FF; outline: none;}
</style>